package com.fastbird.scio.util;

import android.util.Log;

import com.fastbird.ml.PredictRequest;
import com.fastbird.ml.ScioModelImpl;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.reflect.TypeToken;

import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import java.io.InputStreamReader;
import java.io.BufferedReader;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by yangguo on 2017/1/6.
 */
public class ExportUtilsSuit {
    public static String filename = "/Users/yangguo/Desktop/feature"; //id,deviceId,userId,metadata
    private static String fullAttributesOutputFileName = "records.csv";
    private static String scioAttributesOutputFileName = "records.s.csv";
    private static String normAttributesOutputFileName = "records.norm.csv";
    private static String CSV_ROW_SPLIT = "\n";
    private static String CSV_COL_SPLIT = ",";
    private static String SCIO_ID_KEY="udf_customno";
    private static String EMPTY_VALUE="/";

    public static void main(String[] args) throws Exception {
//        transferScioRecordsToCSV("/Users/yangguo/records.22.log", "/Users/yangguo/"); //export version 1
        transferScioRecordsToCSVV2("C:\\Users\\wyd\\Desktop\\www22.log","C:\\Users\\wyd\\Desktop\\records22.csv"); //export version 2
    }

    public static void scioModelSuit() throws Exception {
        InputStreamReader stream = new InputStreamReader(new FileInputStream(filename));
        BufferedReader reader = new BufferedReader(stream);
        List<String> line = new ArrayList<String>();
        String tmp = null;
        double[] noLight = new double[100];
        double[] baseLight = new double[100];
        double[][] series = new double[11][100];//new String[100];
        int index = 0;
        reader.readLine();
        while ((tmp = reader.readLine()) != null) {
            String[] _a = tmp.split("\t");
            noLight[index] = Double.parseDouble(_a[0]);
            baseLight[index] = Double.parseDouble(_a[1]);
            for (int idx = 2; idx < _a.length; idx++) {
                series[idx - 2][index] = Double.parseDouble(_a[idx]);
            }
            index++;
        }

        List<PredictRequest> beans = new ArrayList<PredictRequest>();
        for (int idx = 0; idx < series.length; idx++) {
            PredictRequest bean = new PredictRequest();
            bean.setId(idx + "");
            bean.setBaseLightSeries(baseLight);
            bean.setNoLightSeries(noLight);
            bean.setSeries(series[idx]);
            beans.add(bean);
        }

        ScioModelImpl model = new ScioModelImpl();
//        for (SampleBean bean : beans) {
//             predict = model.predict(bean);
//            String msg = "id-" + bean.getId() + "[";
//            for (Map.Entry<String, Double> entry : predict.entrySet()) {
//                msg += entry.getKey() + ":" + entry.getValue() + ";";
//            }
//            msg += "]";
//            System.out.println(msg);
//        }
    }

    private static void transferScioRecordsToCSVV2(String transferFilePath,String saveFilePath)throws Exception {
        List<ExportsSampleBean> beans = transferScioRecordsFileToList(transferFilePath);
        List<Double> noLight = null;
        List<Double> baseLight = null;
        int index = 1;
        StringBuilder sb = new StringBuilder();
        Collections.sort(beans, new Comparator<ExportsSampleBean>() {
            @Override
            public int compare(ExportsSampleBean o1, ExportsSampleBean o2) {
                int id1 = Integer.parseInt(o1._id);
                int id2 = Integer.parseInt(o2._id);
                return id1 - id2;
            }
        });

        for (ExportsSampleBean bean : beans) {
           Set<String> attributeKeys= bean.attributes.keySet();
            Boolean isExitsScioId=attributeKeys.contains(SCIO_ID_KEY);
            if(baseLight == null){
                sb
                        .append("No").append(CSV_COL_SPLIT)
                        .append("Id").append(CSV_COL_SPLIT)
                        .append("UserID").append(CSV_COL_SPLIT)
                        .append("DeviceId").append(CSV_COL_SPLIT)
                        .append("Time").append(CSV_COL_SPLIT)
                        .append("CustomId").append(CSV_COL_SPLIT);
                for(String key:attributeKeys){
                    if(key!=SCIO_ID_KEY){
                        sb.append(key).append(CSV_COL_SPLIT);
                    }
                }
                writeToSb(sb,bean.label);
                sb.append(CSV_ROW_SPLIT);
            }
            if (noLight == null || !listEq(noLight, bean._noLightSeries)) {
                //id
                noLight = bean._noLightSeries;
                baseLight = bean._baseLightSeries;
                index = 1;
                int aSize = bean.attributes.size();
                if(!isExitsScioId) aSize++;
                sb.append("NoLightSeries").append(CSV_COL_SPLIT);
                writeZeroLineToSb(sb, noLight, aSize-1);
                sb.append("BaseLightSeries").append(CSV_COL_SPLIT);
                writeZeroLineToSb(sb, baseLight, aSize-1);
            }
            sb
                    .append(index).append(CSV_COL_SPLIT)
                    .append(bean._id).append(CSV_COL_SPLIT)
                    .append(bean.userId).append(CSV_COL_SPLIT)
                    .append(bean.deviceId).append(CSV_COL_SPLIT)
                    .append(bean.time).append(CSV_COL_SPLIT);
            if (isExitsScioId) {
                sb.append(bean.attributes.get(SCIO_ID_KEY).toString()).append(CSV_COL_SPLIT);
            } else {
                sb.append(EMPTY_VALUE).append(CSV_COL_SPLIT);
            }
            for (Map.Entry<String, Object> entry : bean.attributes.entrySet()) {
                if (entry.getKey() != SCIO_ID_KEY) {
                    sb.append(entry.getValue()).append(CSV_COL_SPLIT);
                }
            }
            writeToSb(sb, bean._series);
            sb.append(CSV_ROW_SPLIT);
            index++;
        }
        java.io.OutputStream out=new FileOutputStream(new java.io.File(saveFilePath));
        out.write(sb.toString().getBytes());
        out.close();
    }
    private static void writeZeroLineToSb(StringBuilder sb,List<Double> a,int attributeSize){
        int emptyColumnSize=5+attributeSize;//index,id,userId,deviceId,time
        for(int i=0;i<emptyColumnSize;i++){
            sb.append(EMPTY_VALUE).append(CSV_COL_SPLIT);
        }
        writeToSb(sb,a);
        sb.append(CSV_ROW_SPLIT);
    }
    private static void writeToSb(StringBuilder sb,List<Double> a){
        for(Double item:a){
            sb.append(item).append(CSV_COL_SPLIT);
        }
    }
    private static boolean listEq(List<Double> a,List<Double> b){
       /* Boolean isEq=true;
        for(int index=0;index<Math.min(a.size(),b.size());index++){
            if((a.get(index)-(b.get(index)))>0.005) {
                isEq=false;
                break;
            }
        }
        return isEq;*/
       return a.get(0).equals(b.get(0));
    }
    private static List<ExportsSampleBean> transferScioRecordsFileToList(String filePath) throws Exception{
        java.io.InputStreamReader stream = new InputStreamReader(new FileInputStream(filePath));
        java.io.BufferedReader reader = new java.io.BufferedReader(stream);
        List<ExportsSampleBean> beans = new ArrayList<ExportsSampleBean>();
        String lineTxt = null;
        while ((lineTxt = reader.readLine()) != null) {
            System.out.print(lineTxt);
            beans.add(tranferLineData(lineTxt));
        }
        stream.close();
        return beans;
    }
    private static void transferScioRecordsToCSV(String transferFilePath, String savePath) throws Exception {
        List<ExportsSampleBean> beans = transferScioRecordsFileToList(transferFilePath);
        String fullAttrFile = savePath+fullAttributesOutputFileName; //Paths.get(savePath,fullAttributesOutputFileName).toFile();//.toString();
        String sAttrFile = savePath+scioAttributesOutputFileName;
        String normAttrFile = savePath+normAttributesOutputFileName;
        List<String> jsonStrs = writeSampleDataToCSVString(beans);
        outputToFile(jsonStrs.get(0), fullAttrFile);
        outputToFile(jsonStrs.get(1), sAttrFile);
        outputToFile(jsonStrs.get(2), normAttrFile);
    }
    private static void transferScioRecords(String scioRecordsFile,String updateSqlFile) throws Exception{
        java.io.InputStreamReader stream = new InputStreamReader(new FileInputStream(scioRecordsFile));
        java.io.BufferedReader reader = new java.io.BufferedReader(stream);
        ArrayList<Metadata> beans = new ArrayList<Metadata>();
        String lineTxt = null;
        while ((lineTxt = reader.readLine()) != null) {
            String[] idAndData = lineTxt.split("\t");
            if (idAndData.length == 2) {
                beans.add(transferLineToMetadata(idAndData[0], idAndData[1]));
            }
        }
        stream.close();
        StringBuilder builder=new StringBuilder();
        for(Metadata b:beans){
            builder.append(b.toString()).append("\n");
        }
        outputToFile(builder.toString(),updateSqlFile);
    }

    private static void outputToFile(String csvData, String savePath) throws java.io.IOException {
        java.io.FileOutputStream outputStream = new FileOutputStream(savePath);
        outputStream.write(csvData.getBytes());
        outputStream.close();
    }
    private static ExportsSampleBean tranferLineData(String line){
        String[] items=line.split("\\s+");
        //String id=items[0];
        //解决由于编码造成的问题
        String regEx="[^0-9]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(items[0]);
        String id = m.replaceAll("").trim();

        System.out.print("******"+id);
        System.out.print("id:"+id);
        //System.out.println(id);
        String userId=items[1];
        String deviceId=items[2];
        String time = items[3]+" "+items[4];

        Gson gson=new Gson();
        Type type = new TypeToken<Map<String, Object>>() {
        }.getType();
        Map<String, Object> objs = gson.fromJson(items[5], type);
        //System.out.println(items[5]);
        ArrayList<Double> series = (ArrayList<Double>) objs.get("series");
        LinkedTreeMap details = (LinkedTreeMap) objs.get("detail");
        Map<String,Object> attributes=(Map<String,Object>)objs.get("attributes");
        ArrayList<Double> noLightSeries = (ArrayList<Double>) details.get("noLightSeries");
        ArrayList<Double> baseLightSeries = (ArrayList<Double>) details.get("baseLightSeries");
        ArrayList<Double> label=(ArrayList<Double>)objs.get("label");
        return new ExportsSampleBean(id,userId,deviceId,time,attributes,series,noLightSeries,baseLightSeries,label);
    }

    private static ExportsSampleBean tranferLineData(String id, String metadata) throws Exception {
        Gson gson = new Gson();
        Type type = new TypeToken<Map<String, Object>>() {
        }.getType();
        Map<String, Object> objs = gson.fromJson(metadata, type);
        ArrayList<Double> series = (ArrayList<Double>) objs.get("series");
        LinkedTreeMap details = (LinkedTreeMap) objs.get("detail");
        ArrayList<Double> noLightSeries = (ArrayList<Double>) details.get("noLightSeries");
        ArrayList<Double> baseLightSeries = (ArrayList<Double>) details.get("baseLightSeries");
        return new ExportsSampleBean(id, series, noLightSeries, baseLightSeries);
    }
    private static Metadata transferLineToMetadata(String id,String metadata) throws Exception{
        Gson gson = new Gson();
        Type type = new TypeToken<Map<String, Object>>() {
        }.getType();
        Map<String, Object> objs = gson.fromJson(metadata, type);
        String collection=(String) objs.get("collection");
        String collectionId;
        if(collection.contains("酒糟")){
            collectionId="2";
        }else{
            collectionId="1";
        }
        String name=(String)objs.get("name");
        return new Metadata(name,id,collectionId);
    }


    private static ArrayList<String> writeSampleDataToCSVString(List<ExportsSampleBean> beans) throws Exception {
        ArrayList<String> res = new ArrayList<String>();
        int rowSize = Math.max(beans.get(0)._baseLightSeries.size(), beans.get(0)._series.size());
        StringBuilder fullSb = new StringBuilder();
        StringBuilder normSb = new StringBuilder();
        StringBuilder sSb = new StringBuilder();
        ExportsSampleBean bean;
        for (int colIdx = 0; colIdx < beans.size(); colIdx++) {
            String id = beans.get(colIdx)._id;
            fullSb.append(id).append("-s").append(CSV_COL_SPLIT)
                    .append(id).append("-nls").append(CSV_COL_SPLIT)
                    .append(id).append("-bls").append(CSV_COL_SPLIT)
                    .append(id).append("-norm").append(CSV_COL_SPLIT);
            normSb.append(id).append("-norm").append(CSV_COL_SPLIT);
            sSb.append(id).append("-s").append(CSV_COL_SPLIT);
        }
        fullSb.append(CSV_ROW_SPLIT);
        sSb.append(CSV_ROW_SPLIT);
        normSb.append(CSV_ROW_SPLIT);
        String itTemp;
        for (int index = 0; index < rowSize; index++) {
            for (int colIdx = 0; colIdx < beans.size(); colIdx++) {
                bean = beans.get(colIdx);
                if (index < bean._series.size()) {
                    itTemp = bean._series.get(index) + CSV_COL_SPLIT;
                } else {
                    itTemp = "-1" + CSV_COL_SPLIT;
                }
                fullSb.append(itTemp);
                sSb.append(itTemp);
                if (index < bean._noLightSeries.size()) {
                    itTemp = bean._noLightSeries.get(index) + CSV_COL_SPLIT;
                } else {
                    itTemp = "-1" + CSV_COL_SPLIT;
                }
                fullSb.append(itTemp);
                if (index < bean._baseLightSeries.size()) {
                    itTemp = bean._baseLightSeries.get(index) + CSV_COL_SPLIT;
                } else {
                    itTemp = "-1" + CSV_COL_SPLIT;
                }
                fullSb.append(itTemp);
                if (index < bean._avg.size()) {
                    itTemp = bean._avg.get(index) + CSV_COL_SPLIT;
                } else {
                    itTemp = "-1" + CSV_COL_SPLIT;
                }
                fullSb.append(itTemp);
                normSb.append(itTemp);
            }
            fullSb.append(CSV_ROW_SPLIT);
            normSb.append(CSV_ROW_SPLIT);
            sSb.append(CSV_ROW_SPLIT);
        }
        res.add(fullSb.toString());
        res.add(sSb.toString());
        res.add(normSb.toString());
        return res;
    }

    private static class Metadata{
        String id;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getCollectionId() {
            return collectionId;
        }

        public void setCollectionId(String collectionId) {
            this.collectionId = collectionId;
        }

        String collectionId;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        String name;
        public Metadata(String name,String id,String collectionId){
            this.name=name;
            this.id=id;
            this.collectionId=collectionId;
        }

        @Override
        public String toString() {
            return "update tb_records set name='"+name+"' , collection_id='"+collectionId+"' where id='"+id+"';";
        }
    }
    private static class ExportsSampleBean {
        String _id;
        String deviceId;
        String userId;
        String time;
        ArrayList<Double> _series;
        ArrayList<Double> _noLightSeries;
        ArrayList<Double> _baseLightSeries;
        ArrayList<Double> _avg;
        Map<String,Object> attributes;
        List<Double> label;

        /**
         *
         * @param id
         * @param userId
         * @param deviceId
         * @param time
         * @param attributes
         * @param series
         * @param noLightSeries
         * @param baseLightSeries
         * @param label
         */
        public ExportsSampleBean(String id,String userId,String deviceId,String time,Map<String,Object> attributes,ArrayList<Double> series,ArrayList<Double> noLightSeries, ArrayList<Double> baseLightSeries,List<Double> label){
            _id = id;
            _noLightSeries = noLightSeries;
            _baseLightSeries = baseLightSeries;
            _series = series;
            _avg = computeAvg();
            this.userId=userId;
            this.deviceId=deviceId;
            this.time = time;
            this.attributes=attributes;
            this.label=label;
        }
        public ExportsSampleBean(String id, ArrayList<Double> series, ArrayList<Double> noLightSeries, ArrayList<Double> baseLightSeries) {
            this(id,"","","",null,series,noLightSeries,baseLightSeries,null);
        }

        private ArrayList<Double> computeAvg() {
            ArrayList<Double> avg = new ArrayList<Double>();
            for (int idx = 0; idx < this._series.size(); idx++) {
                avg.add((_series.get(idx) - _noLightSeries.get(idx)) / (_baseLightSeries.get(idx) - _noLightSeries.get(idx)));
            }
            return avg;
        }
    }

}
